package aim;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;

public class AIMDumpIndex {  
  private BitManager bm;
  private int position = 0;
  private char[] breakChars;
  
  public AIMDumpIndex() {
    System.out.println("Initializing the index...\n");
    bm = new BitManager();
    try {
      bm = new BitManager();      
      bm.load(Constants.OUTPUT_FILE_NAME);
    } catch(IOException ex) {
      System.err.println("The index file could not be loaded.");
      System.exit(-1);
    }
  }
  
  public char[] getBreakCharArray() {
    return breakChars;    
  }
  
  public int goToFirstDataHeader() {
    position = 0;
    skip(Constants.MONTH_BITS + Constants.DATE_BITS + Constants.YEAR_BITS + 
         Constants.HOUR_BITS + Constants.MINUTE_BITS + Constants.SECOND_BITS);    
    breakChars = getBreakChars().toCharArray();    
    getStopWordFilePath(); //just call this to move the position
        
    return (int)getValue(Constants.NUM_INPUT_FILES_BITS);
  }
  
  /**
   * Determines if a given word is on a given line in this file
   * @param    line    Line number to check
   * @param    checkWord    Word to check for
   * @return    True if word is 'probably' on line, false otherwise
   */
  public boolean isWordOnLine(int filter, int lineNum, String checkWord) {
    
    boolean retval = true;
    String word = checkWord.toLowerCase();
    
    int bitOne = Math.abs(word.hashCode() % Constants.DEFAULT_BITS_PER_BITMASK);
    int bitTwo = Math.abs((word.hashCode() * (lineNum + 2)) % Constants.DEFAULT_BITS_PER_BITMASK);
    int bitThree = Math.abs((word.hashCode() / (lineNum + 2)) % Constants.DEFAULT_BITS_PER_BITMASK);

    if ((filter & (1 << bitOne)) != (1 << bitOne)) {
      retval = false;
    }

    if ((filter & (1 << bitTwo)) != (1 << bitTwo)) {
      retval = false;
    }

    if ((filter & (1 << bitThree)) != (1 << bitThree)) {
      retval = false;
    }
    
    return retval;    
  }
  
  public void skip(int bitsToSkip) {
    position += bitsToSkip;
  }
  
  public int getPosition() {
    return position;
  }
  
  public void setPosition(int position) {
    this.position = position;
  }
  
  public long getValue(int numOfBits) {
    long value = bm.getBits(position, numOfBits);
    position += numOfBits;
    return value;
  }
  
  public String getBreakChars() {
    long bits = getValue(64);
    String bitString = getBits(bits, 64);
    bits = getValue(31);
    bitString += Long.toBinaryString(bits);
    char[] breakChars = bitString.toCharArray();
    
    String customBreakChars = "";    
    for(int c = 0; c < breakChars.length; c++) {
      if(breakChars[c] == '1') {
        int breakChar = Constants.FIRST_CUSTOM_BC + c;
        customBreakChars += (char)breakChar;
      }
    }
    return customBreakChars;
  }
  
  public String getDateTime() {
    int month = (int)getValue(Constants.MONTH_BITS)-1;
    int day = (int)getValue(Constants.DATE_BITS);
    int year = (int)getValue(Constants.YEAR_BITS);
    int hour = (int)getValue(Constants.HOUR_BITS);
    int min = (int)getValue(Constants.MINUTE_BITS);
    int sec = (int)getValue(Constants.SECOND_BITS);    
    
    GregorianCalendar cal = new GregorianCalendar(year, month, day, hour, min, sec);
    SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy kk:mm:ss a");
    return dateFormat.format(cal.getTime());
  }
  
  public String getStopWordFilePath() {
    int stopFileLen = (int)getValue(Constants.FILE_LENGTH_BITS);
    int length = Constants.FILE_LENGTH_BITS*stopFileLen;
    return getStringFromBits(length);
  }
  
  public String getInputFileName() {
    int inFileLen = (int)getValue(Constants.FILE_LENGTH_BITS);
    int length = Constants.FILE_LENGTH_BITS*inFileLen;
    return getStringFromBits(length);
  }
  
  private String getStringFromBits(int length) {
    String bitString = "";
    while(length > 0) {
      int numOfBits = 0;
      for(; numOfBits < 64 && numOfBits < length; numOfBits++);        
      long stopFileBits = getValue(numOfBits);
      bitString += getBits(stopFileBits, numOfBits);
      length -= numOfBits;      
    }
    
    String string = "";
    for(int i = 0; i < bitString.length(); i+=8) {
      String byteString = bitString.substring(i, i+8);
      int ch = Integer.valueOf(byteString, 2).intValue();      
      string += (char)ch;
    }
    return string;
  }

  /**
   * This won't trim the leading zero's like the .toBinaryString method does
   * @param bits
   * @return
   */
  private String getBits(long bits, int bitsToRead) {
    String bitString = "";
    long mask = 1;
    for (int i = 0; i < bitsToRead; i++) {
      long test = bits & mask;
      if (test == mask)
        bitString = "1" + bitString;
      else
        bitString = "0" + bitString;
      mask = mask << 1;
    }
    return bitString;
  }
}
